﻿#region Copyright (c) 2012-10, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using System.IO;
using NUnit.Framework;


namespace Amarok
{
	[TestFixture]
	public class Test_ExceptionExtensions
	{
		#region FindBaseException

		[Test]
		public void Test_FindBaseException_Null()
		{
			var exception = (Exception)null;
			Assert.That(exception.FindBaseException<ApplicationException>(), Is.Null);
		}

		[Test]
		public void Test_FindBaseException_NotFound()
		{
			var exception1 = new InvalidOperationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ArgumentOutOfRangeException("blah", exception2);

			Assert.That(exception3.FindBaseException<ApplicationException>(), Is.Null);
		}

		[Test]
		public void Test_FindBaseException_Found_SuppliedExceptionMatches()
		{
			var exception1 = new ApplicationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ApplicationException("blah", exception2);

			Assert.That(exception3.FindBaseException<ApplicationException>(), Is.SameAs(exception3));
		}

		[Test]
		public void Test_FindBaseException_Found_InnerExceptionMatches()
		{
			var exception1 = new ApplicationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ApplicationException("blah", exception2);
			var exception4 = new ArgumentNullException("blah", exception3);

			Assert.That(exception4.FindBaseException<ApplicationException>(), Is.SameAs(exception3));
			Assert.That(exception4.FindBaseException<ArgumentNullException>(), Is.SameAs(exception4));
			Assert.That(exception4.FindBaseException<ArgumentException>(), Is.SameAs(exception4));
		}

		[Test]
		public void Test_FindBaseException_AggregateException()
		{
			var exception = new AggregateException("0",
				new AggregateException("A1",
					new ApplicationException("B1",
						new OperationCanceledException("B2",
							new ArgumentNullException("B3")
						)
					)
				),
				new AggregateException("C1",
					new InvalidOperationException("D1",
						new AggregateException("D2",
							new InvalidDataException("E1",
								new InvalidCastException("E2")
							),
							new ArgumentException("F1")
						)
					),
					new EndOfStreamException("G1")
				)
			);

			var found1 = exception.FindBaseException<ArgumentException>();
			Assert.That(found1, Is.Not.Null);
			Assert.That(found1.Message, Is.StringContaining("B3"));

			var found2 = exception.FindBaseException<InvalidOperationException>();
			Assert.That(found2, Is.Not.Null);
			Assert.That(found2.Message, Is.StringContaining("D1"));

			var found3 = exception.FindBaseException<EndOfStreamException>();
			Assert.That(found3, Is.Not.Null);
			Assert.That(found3.Message, Is.StringContaining("G1"));

			var found4 = exception.FindBaseException<AggregateException>();
			Assert.That(found4, Is.Not.Null);
			Assert.That(found4.Message, Is.StringContaining("0"));

			var found5 = exception.FindBaseException<InvalidTimeZoneException>();
			Assert.That(found5, Is.Null);
		}

		#endregion

		#region FindBaseExceptions

		[Test]
		public void Test_FindBaseExceptions_Null()
		{
			var exception = (Exception)null;

			var found = exception.FindBaseExceptions<ApplicationException>();

			Assert.That(found, Is.Not.Null);
			Assert.That(found, Is.Empty);
		}

		[Test]
		public void Test_FindBaseExceptions_NotFound()
		{
			var exception1 = new InvalidOperationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ArgumentOutOfRangeException("blah", exception2);

			var found = exception3.FindBaseExceptions<ApplicationException>();

			Assert.That(found, Is.Not.Null);
			Assert.That(found, Is.Empty);
		}

		[Test]
		public void Test_FindBaseExceptions_Found_SuppliedExceptionMatches()
		{
			var exception1 = new ApplicationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ApplicationException("blah", exception2);

			var found = exception3.FindBaseExceptions<ApplicationException>();

			Assert.That(found, Is.Not.Null);
			Assert.That(found, Has.Length.EqualTo(2));
			Assert.That(found, Has.Member(exception1));
			Assert.That(found, Has.Member(exception3));
		}

		[Test]
		public void Test_FindBaseExceptions_Found_InnerExceptionMatches()
		{
			var exception1 = new ApplicationException();
			var exception2 = new EndOfStreamException("blah", exception1);
			var exception3 = new ApplicationException("blah", exception2);
			var exception4 = new ArgumentNullException("blah", exception3);

			var found1 = exception4.FindBaseExceptions<ApplicationException>();

			Assert.That(found1, Is.Not.Null);
			Assert.That(found1, Has.Length.EqualTo(2));
			Assert.That(found1, Has.Member(exception1));
			Assert.That(found1, Has.Member(exception3));

			var found2 = exception4.FindBaseExceptions<EndOfStreamException>();

			Assert.That(found2, Is.Not.Null);
			Assert.That(found2, Has.Length.EqualTo(1));
			Assert.That(found2, Has.Member(exception2));

			var found3 = exception4.FindBaseExceptions<ArgumentException>();

			Assert.That(found3, Is.Not.Null);
			Assert.That(found3, Has.Length.EqualTo(1));
			Assert.That(found3, Has.Member(exception4));
		}

		[Test]
		public void Test_FindBaseExceptions_AggregateException()
		{
			var exception = new AggregateException("0",
				new AggregateException("A1",
					new ApplicationException("B1",
						new OperationCanceledException("B2",
							new ArgumentNullException("B3")
						)
					)
				),
				new AggregateException("C1",
					new InvalidOperationException("D1",
						new AggregateException("D2",
							new InvalidDataException("E1",
								new InvalidCastException("E2")
							),
							new ArgumentException("F1")
						)
					),
					new EndOfStreamException("G1")
				)
			);

			var found1 = exception.FindBaseExceptions<ArgumentException>();
			Assert.That(found1, Is.Not.Null);
			Assert.That(found1, Has.Length.EqualTo(2));
			Assert.That(found1[0].Message, Is.StringContaining("B3"));
			Assert.That(found1[1].Message, Is.StringContaining("F1"));

			var found2 = exception.FindBaseExceptions<InvalidOperationException>();
			Assert.That(found2, Is.Not.Null);
			Assert.That(found2, Has.Length.EqualTo(1));
			Assert.That(found2[0].Message, Is.StringContaining("D1"));

			var found3 = exception.FindBaseExceptions<EndOfStreamException>();
			Assert.That(found3, Is.Not.Null);
			Assert.That(found3, Has.Length.EqualTo(1));
			Assert.That(found3[0].Message, Is.StringContaining("G1"));

			var found4 = exception.FindBaseExceptions<AggregateException>();
			Assert.That(found4, Is.Not.Null);
			Assert.That(found4, Has.Length.EqualTo(4));
			Assert.That(found4[0].Message, Is.StringContaining("0"));
			Assert.That(found4[1].Message, Is.StringContaining("A1"));
			Assert.That(found4[2].Message, Is.StringContaining("C1"));
			Assert.That(found4[3].Message, Is.StringContaining("D2"));

			var found5 = exception.FindBaseExceptions<InvalidTimeZoneException>();
			Assert.That(found5, Is.Not.Null);
			Assert.That(found5, Is.Empty);
		}

		#endregion

		#region GetInnerMostException

		[Test]
		public void Test_GetInnerMostException_NullException()
		{
			Exception exception = null;
			Exception result = exception.GetInnerMostException();

			Assert.That(result, Is.Null);
		}

		[Test]
		public void Test_GetInnerMostException_SingleException()
		{
			Exception exception = new ApplicationException();
			Exception result = exception.GetInnerMostException();

			Assert.That(result, Is.SameAs(exception));
		}

		[Test]
		public void Test_GetInnerMostException_ExceptionChain()
		{
			Exception innerException = new ArgumentNullException();
			Exception exception = new ApplicationException("MSG", innerException);
			Exception result = exception.GetInnerMostException();

			Assert.That(result, Is.SameAs(innerException));
		}

		[Test]
		public void Test_GetInnerMostException_AggregateException()
		{
			Exception exception1 = new ArgumentNullException();
			Exception exception2 = new ApplicationException();
			AggregateException exception = new AggregateException(exception1, exception2);

			Exception result = exception.GetInnerMostException();
			Assert.That(result, Is.SameAs(exception1));
		}

		#endregion

	}
}

#endif
